package com.ma.chapter8.countdownlatch;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.*;

import static com.ma.util.Sleeper.sleep;

/**
 * @ClassName TestCountDownLatch
 * @Author: mayongqiang
 * @DATE 2022/3/26 16:21
 * @Description:
 */
@Slf4j(topic = "m.TestCountDownLatch")
public class TestCountDownLatch {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        test3();
    }

    public static void test3() throws InterruptedException, ExecutionException {
        RestTemplate restTemplate = new RestTemplate();
        /*
         * 1、串行运行所有任务 6s
         * */
        //log.debug("begin");
        //Map<String, Object> res = restTemplate.getForObject("http://localhost:8080/order/{1}", Map.class, 1);
        //log.debug("end order{}",res);
        //
        //Map<String, Object> res1 = restTemplate.getForObject("http://localhost:8080/product/{1}", Map.class, 1);
        //Map<String, Object> res2 = restTemplate.getForObject("http://localhost:8080/product/{2}", Map.class, 1);
        //log.debug("end product-{},{}",res1,res2);
        //Map<String, Object> res3 = restTemplate.getForObject("http://localhost:8080/logistics/{1}", Map.class, 1);
        //log.debug("end logistics {}",res3);

        /*
         * 2、并行运行  2.5s
         * */
        //CountDownLatch latch = new CountDownLatch(4);
        //
        //log.debug("begin");
        //ExecutorService service = Executors.newCachedThreadPool();
        //service.submit(() -> {
        //    Map<String, Object> res = restTemplate.getForObject("http://localhost:8080/order/{1}", Map.class, 1);
        //    log.debug("end order{}", res);
        //    latch.countDown();
        //});
        //service.submit(() -> {
        //    Map<String, Object> res1 = restTemplate.getForObject("http://localhost:8080/product/{1}", Map.class, 1);
        //    log.debug("end product{}", res1);
        //    latch.countDown();
        //
        //});
        //service.submit(() -> {
        //    Map<String, Object> res2 = restTemplate.getForObject("http://localhost:8080/product/{2}", Map.class, 1);
        //    log.debug("end product{}", res2);
        //    latch.countDown();
        //
        //});
        //service.submit(() -> {
        //    Map<String, Object> res3 = restTemplate.getForObject("http://localhost:8080/logistics/{1}", Map.class, 1);
        //    log.debug("end logistics {}", res3);
        //    latch.countDown();
        //
        //});
        //
        //latch.await();
        //log.debug("执行完毕。");


        /*
         * 3、使用Future.get()
         */
        log.debug("begin");
        ExecutorService service = Executors.newCachedThreadPool();
        Future<Map<String, Object>> f1 = service.submit(() -> {
            Map<String, Object> res = restTemplate.getForObject("http://localhost:8080/order/{1}", Map.class, 1);
            return res;
        });
        Future<Map<String, Object>> f2 = service.submit(() -> {
            Map<String, Object> res1 = restTemplate.getForObject("http://localhost:8080/product/{1}", Map.class, 1);
            return res1;
        });
        Future<Map<String, Object>> f3 = service.submit(() -> {
            Map<String, Object> res2 = restTemplate.getForObject("http://localhost:8080/product/{2}", Map.class, 1);
            return res2;
        });

        Future<Map<String, Object>> f4 = service.submit(() -> {
            Map<String, Object> res3 = restTemplate.getForObject("http://localhost:8080/logistics/{1}", Map.class, 1);
            return res3;
        });

        log.debug(String.valueOf(f1.get()));
        log.debug(String.valueOf(f2.get()));
        log.debug(String.valueOf(f3.get()));
        log.debug(String.valueOf(f4.get()));
        log.debug("完成");

    }

    private static void method2() throws InterruptedException {
        // 应用-等待多线程准备完毕
        /*
         * CountDownLatch 实现 等待所有玩家全部加载完毕 开始游戏
         * */
        CountDownLatch latch = new CountDownLatch(10);
        ExecutorService service = Executors.newFixedThreadPool(10);
        String[] all = new String[10];
        Random random = new Random();
        for (int k = 0; k < 10; k++) {
            int finalK = k;
            service.submit(() -> {
                for (int i = 0; i <= 100; i++) {
                    try {
                        Thread.sleep(random.nextInt(100));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 是局部变量  lamda表达式只能用局部常量
                    all[finalK] = i + "%";
                    // 加入回车符 \r  可以让后面的打印结果覆盖到刚才的打印上
                    System.out.print("\r" + Arrays.toString(all));
                }
                latch.countDown();
            });
        }
        latch.await();
        System.out.println("\n游戏开始");
        service.shutdown();
    }

    /*
     * 配合线程池使用 某一个线程等待其他三个线程结束后汇总
     * */
    private static void methodPool() {
        CountDownLatch latch = new CountDownLatch(3);

        ExecutorService service = Executors.newFixedThreadPool(4);
        service.submit(() -> {
            log.debug("begin...");
            sleep(1);
            latch.countDown();
            log.debug("end...{}", latch.getCount());
        });
        service.submit(() -> {
            log.debug("begin...");
            sleep(1.5);
            latch.countDown();
            log.debug("end...{}", latch.getCount());
        });
        service.submit(() -> {
            log.debug("begin...");
            sleep(2);
            latch.countDown();
            log.debug("end...{}", latch.getCount());
        });
        service.submit(() -> {
            try {
                log.debug("waiting...");
                latch.await();
                log.debug("wait end...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }

    /*
     * CountDownLatch的基本使用
     */
    private static void method1() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3);
        new Thread(() -> {
            log.debug("begin...");
            sleep(1);
            latch.countDown();
            log.debug("end...{}", latch.getCount());
        }).start();
        new Thread(() -> {
            log.debug("begin...");
            sleep(2);
            latch.countDown();
            log.debug("end...{}", latch.getCount());
        }).start();
        new Thread(() -> {
            log.debug("begin...");
            sleep(1.5);
            latch.countDown();
            log.debug("end...{}", latch.getCount());
        }).start();
        log.debug("waiting...");
        latch.await();
        log.debug("wait end...");
    }
}
